#include <boost/regex.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>

#include "cfg_parser.h"

const std::string kFunctDeclaration = ";; Function";

const boost::regex reg_bb("^<bb (\\d+)>");

const boost::regex reg_goto("goto <bb (\\d+)>");

using namespace boost::filesystem;

CfgParser::CfgParser(CfgCallbacks* callbacks)
    :   callbacks_(callbacks)
{
}
void CfgParser::ParseFile(Context& context, const std::string& path_str)
{
    ifstream file(path_str);
    std::stringstream content;
    content << file.rdbuf();
    std::string line;
    boost::smatch results;

    while (content) {
        getline(content, line);
        if (! line.compare(0, kFunctDeclaration.length(), kFunctDeclaration)) {
            int pos_fun_decl_begin = kFunctDeclaration.length();
            int id_end_pos = line.length() - 2;
            int pos = id_end_pos;
            while (line[pos] != '(') {
                pos--;
            }
            std::string func_id(line, pos + 1, id_end_pos - pos);
            std::string func_name(line, pos_fun_decl_begin, pos - pos_fun_decl_begin-1);
            callbacks_->OnFunctionBegin(context, func_name, func_id);
            ParseFunction(context, content);
            callbacks_->OnFunctionEnd(context);
        }
    }
}

void CfgParser::ParseFunction(Context& context, std::stringstream& content)
{
    std::string line;
    bool in_block = false;
    boost::smatch results;
    while (content) {
        getline(content, line);
        if (! line.compare("}")) {
            break;
        }
        boost::trim(line);
        std::cout <<line <<"\n";
        std::string::const_iterator xItStart = line.begin();
        std::string::const_iterator xItEnd = line.end();
        if (boost::regex_search(xItStart, xItEnd, results, reg_bb)) {
            std::string str(results[1].first, results[1].second);
            in_block = true,
            callbacks_->OnBlock(context, ::atoi(str.c_str()));
        }
        else if (boost::regex_search(xItStart, xItEnd, results, reg_goto)) {
            std::string str(results[1].first, results[1].second);
            callbacks_->OnGoto(context, ::atoi(str.c_str()));
        }
        else if (in_block) {
            callbacks_->AddCodeLine(context, line);
        }
    }
}
